#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include"requestor.hpp"
#include<unordered_set>
namespace RPC_project
{
    namespace client
    {
        class TopicManager
        {
            public:
                using subCallback =std::function<void(const std::string& key ,const std::string& message)>; //主题名称  消息内容
                using ptr =std::shared_ptr<TopicManager>;
                TopicManager(Requestor::ptr requestor):_requestor(requestor)
                {}

                //提供给用户的5个接口
                bool creatTopic(const BaseConnection::ptr & conn , const std::string &key)
                {
                    return commonRequest(conn, key ,TopicOptype::TOPIC_CREATE);

                }
                bool removeTopic(const BaseConnection::ptr & conn ,const std::string &key)
                {
                    return commonRequest(conn, key ,TopicOptype::TOPIC_REMOVE);
                }
                bool subscribeTopic(const BaseConnection::ptr & conn ,const std::string &key,const subCallback& cb)//订阅主题 ，设置收到消息后的回调函数
                {
                    //建立映射关系
                    addSubscribe(key,cb);
                    bool ret =commonRequest(conn, key ,TopicOptype::TOPIC_SUBSCRIBE);
                    if(ret == false)
                    {
                        delSubscribe(key);
                        return false;
                    }
                    return true;
                }
                bool cannel(const BaseConnection::ptr & conn  , const std::string &key)//取消一个主题的订阅
                {
                    delSubscribe(key);
                    return commonRequest(conn, key ,TopicOptype::TOPIC_CANCEL);

                }
                bool publish(const BaseConnection::ptr & conn , const std::string &key ,const std::string& message)
                {
                    return commonRequest(conn, key ,TopicOptype::TOPIC_PUBLISH, message);
                }

                //提供给dispatcher的接口 ,客户端只会收到“消息发布请求”
                void onPublishRequest(const BaseConnection::ptr& conn ,const TopicRequest::ptr &msg)
                {
                    //1.从消息中取出操作类型 ，判断是否是消息发布请求
                    //2.取出消息主题名称，以及消息内容
                    //3.通过主题名称，查找主题的回调处理函数 ，有就处理 ，没有就报错

                    //1. 从消息中取出操作类型进行判断，是否是消息请求
                    auto type = msg->OpType();
                    if (type != TopicOptype::TOPIC_PUBLISH) {
                        ELOG("收到了错误类型的主题操作！");
                        return ;
                    }
                    //2. 取出消息主题名称，以及消息内容
                    std::string topic_key = msg->TopickKey();
                    std::string topic_msg = msg->TopickMsg();
                    //3. 通过主题名称，查找对应主题的回调处理函数，有在处理，无在报错
                    auto callback = getSubscribe(topic_key);
                    if (!callback) {
                        ELOG("收到了 %s 主题消息，但是该消息无主题处理回调！", topic_key.c_str());
                        return ;
                    }
                    return callback(topic_key, topic_msg);

                }
            private:
                void addSubscribe(const std::string &key,const subCallback& cb)
                {
                    
                        std::unique_lock<std::mutex> lock(_mutex);
                        _topic_callback.insert(std::make_pair(key, cb));
                    
                }
                void delSubscribe(const std::string &key)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _topic_callback.erase(key);
                }
                const subCallback getSubscribe(const std::string &key)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it=_topic_callback.find(key);
                    if(it ==_topic_callback.end() )
                    {
                        return subCallback();
                    }
                    return it->second;
                }

                bool commonRequest(const BaseConnection::ptr & conn , const std::string &key ,TopicOptype optype , const std::string& message= "")
                {
                    //1.构建请求对象 ，并填充数据
                    auto msg_request =MessageFactory::Create(MType::REQ_TOPIC);
                    RPC_project::TopicRequest::ptr topic_req = std::dynamic_pointer_cast<RPC_project::TopicRequest>(msg_request);
                    topic_req->Setid(UUID::uuid());
                    topic_req->SetMyType(MType::REQ_TOPIC);
                    topic_req->SetOpType(optype);
                    topic_req->SetTopickKey(key);//主题名称
                    if(optype ==TopicOptype::TOPIC_PUBLISH)
                    {
                        topic_req->SetTopickMsg(message);
                    }
                    //2.向服务端发送请求 ，等待响应
                    BaseMessage::ptr msg_response;
                    bool ret =_requestor->sync_send(conn ,topic_req , msg_response);//同步式的等待响应
                    if (ret == false)
                    {
                        ELOG("主题操作请求失败");
                        return false;
                    }
                    //3.判断请求处理是否成功
                    auto topic_rsp_msg = std::dynamic_pointer_cast<TopicResponse>(msg_response);
                    if (!topic_rsp_msg)
                    {
                        ELOG("主题操作响应,向下类型转换失败！");
                        return false;
                    }
                    if (topic_rsp_msg->Rcode() != RCode::RCODE_OK)
                    {
                        ELOG("主题操作请求出错: %s", errReason(topic_rsp_msg->Rcode()).c_str());
                        return false;
                    }
                    return true;
                }
            private:
                std::mutex _mutex;
                std::unordered_map<std::string ,subCallback> _topic_callback;
                Requestor::ptr _requestor;//requestor进行请求的发送和响应的管理
        };

    }
}